﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using TLM.PlaylistGenerator.Model;
using TLM.VsmdiReader;
using Microsoft.VisualStudio.TestTools.Vsip;
using Microsoft.VisualStudio.TestTools.Common;
using System.IO;
using System.Globalization;

namespace TLM.PlaylistGenerator
{
    /// <summary>
    /// This class contains all the logic for generating playlists from VSMDI objects.
    /// </summary>
    public class Generator
    {
        private ITestManagement _tmiInstance;

        private const string PLAYLIST_FILENAME = "aggregate.playlist";

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="tmiInstance">The TMI instance of the project</param>
        public Generator(ITestManagement tmiInstance)
        {
            if (tmiInstance == null)
            {
                throw new ArgumentNullException("tmiInstance");
            }

            // We need the TMI Instance to be able to determine the Fully Qualified Name of a test
            _tmiInstance = tmiInstance;
        }

        /// <summary>
        /// Generate all the playlists and store the xml content in the <see cref="VsmdiFile"/> object 
        /// </summary>
        /// <param name="vsmdiObject">The vsmdi object containing the testlists to migrate</param>
        /// <param name="saveFolder">The folder to save the playlists too</param>
        /// <param name="askOverwriteFile">Delegate to handle permission request to overwrite files which already exist</param>
        public void CreatePlaylists(VsmdiFile vsmdiObject, string saveFolder, Func<string, bool> askOverwriteFile)
        {
            if (vsmdiObject == null)
            {
                throw new ArgumentNullException("vsmdiObject");
            }

            // Recursively convert and save all child lists
            CreateChildPlaylists(saveFolder, Enumerable.Repeat(vsmdiObject.ListOfTests, 1), askOverwriteFile);
        }

        private void CreateChildPlaylists(string saveFolder, IEnumerable<TestList> childTestLits, Func<string, bool> askOverwriteFile)
        {
            foreach (TestList testList in childTestLits)
            {
                string directoryPath = CreateDirectoryIfNotExists(saveFolder, testList.Name);
                CreatePlaylist(testList, directoryPath, askOverwriteFile);
                CreateChildPlaylists(directoryPath, testList.ChildLists, askOverwriteFile);
            }
        }

        private void CreatePlaylist(TestList testList, string saveFolder, Func<string, bool> askOverwriteFile)
        {
            // First test list is usually ListOfTests, we convert and save this one seperately
            Playlist rootPlaylist = testList.ConvertToPlaylist(_tmiInstance.TmiInstance);
            string xmlRootPlaylist = GenerateXml(rootPlaylist);
            SavePlayListFile(saveFolder, PLAYLIST_FILENAME, xmlRootPlaylist, askOverwriteFile);
        }

        /// <summary>
        /// Generates XML from the specified playlist and returns it as a string.
        /// </summary>
        /// <param name="playlist">The playlist that has to be parsed to XML.</param>
        /// <returns>The full XML of the parsed playlist.</returns>
        private string GenerateXml(Playlist playlist)
        {
            if (playlist == null)
            {
                throw new ArgumentNullException("playlist");
            }

            string xmlContent = string.Empty;
            using (TextWriter xmlWriter = new StringWriter(new CultureInfo("en-US")))
            {
                XmlSerializer xs = new XmlSerializer(typeof(Playlist));
                xs.Serialize(xmlWriter, playlist);
                xmlContent = xmlWriter.ToString();
            }
            return xmlContent;
        }

        /// <summary>
        /// Creates a directory in the specified base path with the specified directory name.
        /// </summary>
        /// <param name="basePath">The path where the new directory has to be created.</param>
        /// <param name="directoryName">The name of the new directory.</param>
        /// <returns>The full path to the new directory</returns>
        private string CreateDirectoryIfNotExists(string basePath, string directoryName)
        {
            string fullPath = Path.Combine(basePath, directoryName);

            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(fullPath);
            }

            return fullPath;
        }

        /// <summary>
        /// Saves a file with the specified XML to the specified location on the disk.
        /// </summary>
        /// <param name="savePath">The location where the playlist has to be saved.</param>
        /// <param name="fileName">The filename of the playlist.</param>
        /// <param name="xmlContents">The XML content that has to be placed in the file.</param>
        /// <param name="askOverwrite">Delegate to handle situations where files already exist.</param>
        private void SavePlayListFile(string savePath, string fileName, string xmlContents, Func<string, bool> askOverwrite)
        {
            string fullSavePath = Path.Combine(savePath, fileName);

            if (File.Exists(fullSavePath))
            {
                if (!askOverwrite(fullSavePath))
                {
                    return;
                }
            }

            File.WriteAllText(fullSavePath, xmlContents);
        }
    }

    
}